\section{字符串}

Python中的字符串（Strings）是用单引号或双引号标记的一系列连续字符（characters），换句话说，字符串是由单个字符组成的序列（list）。即便只有一个字符，也是字符串，Python中没有字符数据类型。

\subsection{创建字符串}

\begin{lstlisting}
>>> name = "tom"
>>> mychar = 'a'
\end{lstlisting}

我们还可以使用下面的语法创建字符串：

\begin{lstlisting}
>>> name1 = str() # 创建一个空字符串
>>> name2 = str("newstring") # 创建一个内容为newstring的字符串
\end{lstlisting}

\subsection{字符串的不可变性}

在Python中，每一个对象都可以分为不可变性或者可变性。在核心类型中，数字、字符串和元组是不可变的。

字符串在Python中一旦创建就不能就地改变，例如不能通过对其某一位置进行赋值而改变字符串。下面的语句就会出现如下语法错误：“TypeError: 'str' object does not support item assignment”。

\begin{lstlisting}
s = 'string'
print(len(s))
print(s[0])  				# 输出序列的第一个元素
s[0] = 'another s' 	# 试图修改字符串的内容
print(s)
\end{lstlisting}

关于不可变性，我们再看一个例子：

\begin{lstlisting}
>>> str1 = "welcome"
>>> str2 = "welcome"
\end{lstlisting}

上述代码中，str1和str2都指向存储在内存中某个地方的字符串对象"welcome"。我们可以通过id()函数来测试str1和str2是否真的指向同一个对象。

\begin{myremark}{id()函数}
id()函数可以得到对象在内存中的存储地址。
\end{myremark}

如下：

\begin{lstlisting}
>>> str1 = 'welcome'
>>> str2 = 'welcome'
>>> id(str1)
35462112
>>> id(str2)
35462112
\end{lstlisting}

我们可以看到，str1和str2都指向同一个内存地址，因此，他们都指向同样的对象“welcome”。下面让我们再编辑str1的内容看看：

\begin{lstlisting}
>>> str1 += " yangjh"
>>> str1
'welcome yangjh'
>>> id(str1)
35487600
\end{lstlisting}

我们可以看到，现在变量str1指向了一个完全不同的内容地址，这也说明，我们对str1的内容操作实际上是新建了一个新的字符串对象。

\subsection{字符串操作}

字符串索引开始于0，因此，我们可以这样获取字符串的第一个字符：

\begin{lstlisting}
>>> name = 'yangjh'
>>> name[0]
'y'
\end{lstlisting}

在对字符串操作时，还可以从后往前取元素：

\begin{lstlisting}
>>> name[-1]
'h'
\end{lstlisting}

运算符“+”用来连接字符串，运算符“*”用来重复字符串，例如：

\begin{lstlisting}
>>> s = "tom and " + "jerry"
>>> print(s)
tom and jerry
>>> s = "love " * 3
>>> print(s)
love love love
\end{lstlisting}

\subsection{字符串分片}
我们还可以通过“[]”操作符来获取原始字符串的子集，这就是所谓的分片。语法规则如下：

\begin{lstlisting}
s[start:end]
\end{lstlisting}

切分操作将返回字符串的部分内容，起始于index，结束于end-1。例如：

\begin{lstlisting}
>>> s = 'yangjh'
>>> s[1:3]
'an'
>>> s = "Welcome"
>>> s[ : 6]
'Welcom'
>>> s[4 : ]
'ome'
>>> s[1 : -1]
'elcom'
\end{lstlisting}

注意：开始索引和结束索引都是可选的，如果忽略，开始索引就是0，而结束索引就是字符串的最后一个字符对应的索引值。

\subsection{in 和 not in 操作符}

我们可以使用in和not in操作符检查一个字符串是否存在于另一个字符串，in和not in就是所谓的成员资格操作符（membership operator）。

\begin{lstlisting}
>>> s1 = "Welcome"
>>> "come" in s1
True
>>> "come" not in s1
False
\end{lstlisting}

\subsection{String对象的方法}

下表\ref{tab:常用的字符串方法}是三个常用的字符串方法：
% Table generated by Excel2LaTeX from sheet 'Sheet1'
\begin{table}[ht]
  \centering
  \caption{常用的字符串方法}
    \begin{tabular}{ll}
    \toprule
    \textbf{方法名称} & \textbf{功能描述} \\
    \midrule
    len()   & 返回字符串长度 \\
    max()   & 返回字符串中ASCII编码值最大的字符 \\
    min()   & 返回字符串中ASCII编码值最小的字符 \\
    \bottomrule
    \end{tabular}%
  \label{tab:常用的字符串方法}%
\end{table}%

\begin{lstlisting}
>>> len("hello")
5
>>> max("abc")
'c'
>>> min("abc")
'a'
\end{lstlisting}

\subsection{比较字符串}

我们可以使用( > , < , <= , <= , == , !=  ) 比较两个字符串。Python比较字符串是按照编纂字典的方式进行的，也就是使用\href{http://tool.oschina.net/commons?type=4}{ASCII编码值}\footnote{美国信息交换标准码(American Standard Code for Information Interchange)是由美国国家标准学会(American National Standard Institute,ANSI)制定的单字节字符编码方案，供不同计算机在相互通信时用作共同遵守的西文字符编码标准，它已被国际标准化组织（ISO）定为国际标准，称为ISO646标准。}比较字符。

假设str1的值为"Jane"，str2的值为"Jake"，首先比较这两个字符串的第一个字符“J”，如果相等，就继续比较第二个字符（a和a），因为相同，所以继续比较第三个字符（n和k），因为n的ASCII编码值大于k，因此str1大于str2。更多例子参见下面的代码：

\begin{lstlisting}
>>> "tim" == "tie"
False
>>> "free" != "freedom"
True
>>> "arrow" > "aron"
True
>>> "green" >= "glow"
True
>>> "green" < "glow"
False
>>> "green" <= "glow"
False
>>> "ab" <= "abc"
True
\end{lstlisting}

\subsection{遍历字符串}

字符串是序列，因此也可以使用循环遍历成员。

\begin{lstlisting}
>>> s = "yangjh"
>>> for i in s:
...     print(i, end="")
...
yangjh
\end{lstlisting}

\begin{myremark}{改变print()函数的输出格式}
print()函数在默认状态下，会另起一行打印字符串，我们可以使用第二个参数修改结束标记。如
print("my string", end="")就表示打印字符串，但不另起一行。
\end{myremark}

\subsection{字符串内容检验}

Python字符串类内置了丰富的方法，使用这些方法（见表\ref{tab:字符串内容检验}），我们可以检查字符串内容的类型。

% Table generated by Excel2LaTeX from sheet 'Sheet1'
\begin{table}[ht]
  \centering
  \caption{字符串内容类型检验方法}
    \begin{tabular}{ll}
    \toprule
    \textbf{方法名称} & \textbf{方法说明} \\
    \midrule
    isalnum() 			& 如果 string 包含字符都是字母或数字则返回 True \\
    isalpha() 			& 如果string包含字符都是字母则返回True \\
    isdigit() 			& 如果string包含字符都是数字则返回True \\
    isidentifier() 	& 判断字符串是否是合格的标识名 \\
    islower() 			& 判断字符串中是否都是小写字母 \\
    isupper() 			& 判断字符串中是否都是大写字母 \\
    isspace() 			& 判断字符串是否由空格组成 \\
    \bottomrule
    \end{tabular}%
  \label{tab:字符串内容检验}%
\end{table}%

这些判断方法的实例如下：

\begin{lstlisting}
>>> s = "welcome to python"
>>> s.isalnum()
False
>>> "Welcome".isalpha()
True
>>> "2012".isdigit()
True
>>> "first Number".isidentifier()
False
>>> s.islower()
True
>>> "WELCOME".isupper()
True
>>> "  \t".isspace()
True
\end{lstlisting}

\subsection{在字符串内查找和替换}

除了一般的序列操作，字符串还有独有的一些方法。如查找和替换：

\begin{lstlisting}
print(s.find('in'))
print(s.replace('g', 'gs'))  # 虽然显示字符串已被替换，但实际上是一个新的字符串。
\end{lstlisting}

相关的方法见下表\ref{tab:查找子字符串}：

% Table generated by Excel2LaTeX from sheet 'Sheet1'
\begin{table}[ht]
  \centering
  \caption{查找子字符串}
    \begin{tabularx}{\linewidth}{p{6cm}|X}
    \toprule
    \textbf{方法名称} & \textbf{方法说明} \\
    \midrule
    endswith(s1: str): bool 	& 如果字符串以指定的字符串结尾，则返回真 \\
    startswith(s1: str): bool & 如果字符串以指定的字符串开始，则返回真 \\
    count(substring): int 		& 返回子字符串在字符串中出现的次数 \\
    find(s1): int 						& 返回子字符串在字符串中第一次出现的索引，如果没有，则返回-1 \\
    rfind(s1): int 						& 返回子字符串在字符串中最后一次出现的索引，如果没有，则返回-1 \\
    \bottomrule
    \end{tabularx}%
  \label{tab:查找子字符串}%
\end{table}%

示例如下：

\begin{lstlisting}
>>> s = "welcome to python"
>>> s.endswith("thon")
True
>>> s.startswith("good")
False
>>> s.find("come")
3
>>> s.find("become")
-1
>>> s.rfind("o")
15
>>> s.count("o")
3
\end{lstlisting}


